#include "downloaditem.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QUrl>
#include <QtCore/QStandardPaths>
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>

DownloadItem::DownloadItem(const QString &url, QObject *parent)
    : QObject(parent)
    , m_url(url)
    , m_fileSize(0)
    , m_downloadedSize(0)
    , m_status(Queued)
    , m_progress(0)
    , m_category("Default")
    , m_retryCount(0)
    , m_maxRetries(3) // 默认最大重试3次
    , m_maxConnections(5) // 默认5个并发连接以提高速度
    , m_reply(nullptr)
    , m_file(nullptr)
    , m_retryTimer(new QTimer(this))
    , m_speedTimer(new QTimer(this))
    , m_lastDownloadedSize(0)
    , m_downloadSpeed(0)
{
    updateFileName();
    
    // 设置默认保存路径
    QString downloadPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
    if (downloadPath.isEmpty()) {
        downloadPath = QDir::currentPath();
    }
    m_savePath = downloadPath + QDir::separator() + m_fileName;
    
    // 根据文件扩展名设置默认分类
    QFileInfo fileInfo(m_fileName);
    QString suffix = fileInfo.suffix().toLower();
    if (!suffix.isEmpty()) {
        if (suffix == "jpg" || suffix == "jpeg" || suffix == "png" || suffix == "gif" || suffix == "bmp") {
            m_category = "Images";
        } else if (suffix == "mp4" || suffix == "avi" || suffix == "mkv" || suffix == "mov" || suffix == "wmv") {
            m_category = "Videos";
        } else if (suffix == "mp3" || suffix == "wav" || suffix == "flac" || suffix == "aac" || suffix == "ogg") {
            m_category = "Audio";
        } else if (suffix == "pdf" || suffix == "doc" || suffix == "docx" || suffix == "txt" || suffix == "rtf") {
            m_category = "Documents";
        } else if (suffix == "zip" || suffix == "rar" || suffix == "7z" || suffix == "tar" || suffix == "gz") {
            m_category = "Archives";
        } else if (suffix == "exe" || suffix == "msi" || suffix == "bat" || suffix == "sh") {
            m_category = "Software";
        }
    }
    
    // 设置重试定时器
    connect(m_retryTimer, &QTimer::timeout, this, &DownloadItem::onRetryTimeout);
    m_retryTimer->setSingleShot(true); // 单次触发
    
    // 设置速度计算定时器
    connect(m_speedTimer, &QTimer::timeout, [=]() {
        qint64 currentSize = m_downloadedSize;
        m_downloadSpeed = (currentSize - m_lastDownloadedSize);
        m_lastDownloadedSize = currentSize;
        emit downloadSpeedChanged(m_downloadSpeed);
    });
    m_speedTimer->setInterval(1000); // 每秒计算一次速度
}

DownloadItem::~DownloadItem()
{
    stopMultiThreadDownload();
    
    if (m_reply) {
        m_reply->deleteLater();
    }
    
    if (m_file) {
        m_file->close();
        m_file->deleteLater();
    }
}

QString DownloadItem::url() const
{
    return m_url;
}

QString DownloadItem::fileName() const
{
    return m_fileName;
}

qint64 DownloadItem::fileSize() const
{
    return m_fileSize;
}

qint64 DownloadItem::downloadedSize() const
{
    return m_downloadedSize;
}

DownloadItem::Status DownloadItem::status() const
{
    return m_status;
}

int DownloadItem::progress() const
{
    return m_progress;
}

QDateTime DownloadItem::startTime() const
{
    return m_startTime;
}

QDateTime DownloadItem::endTime() const
{
    return m_endTime;
}

QString DownloadItem::savePath() const
{
    return m_savePath;
}

int DownloadItem::downloadSpeed() const
{
    return m_downloadSpeed;
}

QString DownloadItem::category() const
{
    return m_category;
}

QStringList DownloadItem::tags() const
{
    return m_tags;
}

int DownloadItem::retryCount() const
{
    return m_retryCount;
}

int DownloadItem::maxRetries() const
{
    return m_maxRetries;
}

void DownloadItem::setMaxRetries(int maxRetries)
{
    m_maxRetries = maxRetries;
}

void DownloadItem::setSavePath(const QString &path)
{
    m_savePath = path;
}

void DownloadItem::setMaxConnections(int max)
{
    m_maxConnections = max;
}

void DownloadItem::setSpeedLimit(int limitKBps)
{
    m_speedLimit = limitKBps;
}

void DownloadItem::setCategory(const QString &category)
{
    m_category = category;
}

void DownloadItem::setTags(const QStringList &tags)
{
    m_tags = tags;
}

void DownloadItem::start()
{
    if (m_status == Downloading) {
        return;
    }
    
    m_status = Downloading;
    emit statusChanged(m_status);
    
    m_startTime = QDateTime::currentDateTime();
    m_speedTimer->start();
    m_lastDownloadedSize = 0;
    m_downloadSpeed = 0;
    
    // 打开文件用于写入
    if (!m_file) {
        m_file = new QFile(m_savePath, this);
    }
    
    if (!m_file->isOpen()) {
        if (!m_file->open(QIODevice::WriteOnly | QIODevice::Append)) {
            emit downloadError(QString("无法打开文件: %1").arg(m_savePath));
            m_status = Error;
            emit statusChanged(m_status);
            return;
        }
    }
    
    // 如果设置了多线程下载，则使用多线程方式
    if (m_maxConnections > 1) {
        startMultiThreadDownload();
    } else {
        // 单线程下载
        QNetworkAccessManager *manager = new QNetworkAccessManager(this);
        
        // 优化网络管理器设置
        manager->setAutoDeleteReplies(true);
        
        QNetworkRequest request;
        request.setUrl(QUrl(m_url));
        
        // 设置一些HTTP头以提高兼容性
        request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
        request.setRawHeader("Accept", "*/*");
        request.setRawHeader("Accept-Encoding", "identity");
        request.setRawHeader("Connection", "keep-alive");
        
        // 如果之前已经下载了一部分，设置断点续传
        if (m_downloadedSize > 0) {
            QString range = QString("bytes=%1-").arg(m_downloadedSize);
            request.setRawHeader("Range", range.toLatin1());
        }
        
        m_reply = manager->get(request);
        
        connect(m_reply, &QNetworkReply::readyRead, this, &DownloadItem::onReadyRead);
        connect(m_reply, &QNetworkReply::finished, this, &DownloadItem::onFinished);
        connect(m_reply, &QNetworkReply::errorOccurred, this, &DownloadItem::onError);
        connect(m_reply, &QNetworkReply::downloadProgress, 
                this, &DownloadItem::onDownloadProgress);
    }
}

void DownloadItem::pause()
{
    if (m_status != Downloading) {
        return;
    }
    
    m_speedTimer->stop();
    
    if (m_maxConnections > 1) {
        stopMultiThreadDownload();
    } else {
        if (m_reply) {
            m_reply->abort();
        }
    }
    
    // 关闭文件
    if (m_file && m_file->isOpen()) {
        m_file->close();
    }
    
    m_status = Paused;
    emit statusChanged(m_status);
}

void DownloadItem::cancel()
{
    m_speedTimer->stop();
    m_retryTimer->stop(); // 停止重试定时器
    
    if (m_maxConnections > 1) {
        stopMultiThreadDownload();
    } else {
        if (m_reply) {
            m_reply->abort();
            m_reply->deleteLater();
            m_reply = nullptr;
        }
    }
    
    // 关闭并删除文件
    if (m_file) {
        if (m_file->isOpen()) {
            m_file->close();
        }
        m_file->deleteLater();
        m_file = nullptr;
    }
    
    m_status = Canceled;
    m_progress = 0;
    m_downloadedSize = 0;
    m_downloadSpeed = 0;
    m_retryCount = 0; // 重置重试次数
    
    emit statusChanged(m_status);
    emit progressChanged(m_progress);
    emit downloadSpeedChanged(m_downloadSpeed);
}

void DownloadItem::onReadyRead()
{
    if (!m_reply || !m_file) {
        return;
    }
    
    QByteArray data = m_reply->readAll();
    m_downloadedSize += data.size();
    m_file->write(data);
    m_file->flush(); // 立即刷新到磁盘
}

void DownloadItem::onFinished()
{
    if (!m_reply) {
        return;
    }
    
    if (m_reply->error() == QNetworkReply::NoError) {
        m_status = Completed;
        m_endTime = QDateTime::currentDateTime();
        m_speedTimer->stop();
        m_retryCount = 0; // 下载成功，重置重试次数
        
        // 关闭文件
        if (m_file && m_file->isOpen()) {
            m_file->close();
        }
        
        emit statusChanged(m_status);
        emit downloadFinished();
    } else {
        // 发生错误时更新状态和错误信息
        m_status = Error;
        m_speedTimer->stop();
        
        // 关闭文件
        if (m_file && m_file->isOpen()) {
            m_file->close();
        }
        
        emit statusChanged(m_status);
        emit downloadError(m_reply->errorString());
        
        // 安排重试
        scheduleRetry();
    }
    
    m_reply->deleteLater();
    m_reply = nullptr;
}

void DownloadItem::onError(QNetworkReply::NetworkError error)
{
    Q_UNUSED(error);
    
    if (!m_reply) {
        return;
    }
    
    m_speedTimer->stop();
    m_status = Error;
    emit statusChanged(m_status);
    emit downloadError(m_reply->errorString());
    
    // 安排重试
    scheduleRetry();
}

void DownloadItem::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    m_downloadedSize = bytesReceived;
    m_fileSize = bytesTotal;
    
    if (bytesTotal > 0) {
        m_progress = static_cast<int>((bytesReceived * 100) / bytesTotal);
        emit progressChanged(m_progress);
    }
}

void DownloadItem::onSegmentReadyRead()
{
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
    if (!reply) return;
    
    int segmentIndex = m_replies.indexOf(reply);
    if (segmentIndex == -1) return;
    
    QByteArray data = reply->readAll();
    m_segmentDownloaded[segmentIndex] += data.size();
    m_downloadedSize += data.size();
    
    // 计算该段数据在文件中的位置
    qint64 position = 0;
    for (int i = 0; i < segmentIndex; ++i) {
        position += m_segmentSizes[i];
    }
    position += (m_segmentDownloaded[segmentIndex] - data.size());
    
    // 写入数据到文件的指定位置
    if (m_file) {
        m_file->seek(position);
        m_file->write(data);
        m_file->flush(); // 立即刷新到磁盘
    }
}

void DownloadItem::onSegmentFinished()
{
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
    if (!reply) return;
    
    int segmentIndex = m_replies.indexOf(reply);
    if (segmentIndex == -1) return;
    
    if (reply->error() != QNetworkReply::NoError) {
        // 某个段发生错误，停止所有下载
        m_speedTimer->stop();
        m_status = Error;
        emit statusChanged(m_status);
        emit downloadError(reply->errorString());
        
        // 停止所有其他段的下载
        stopMultiThreadDownload();
        
        // 安排重试
        scheduleRetry();
        return;
    }
    
    // 检查是否所有段都已完成
    bool allFinished = true;
    for (QNetworkReply *r : qAsConst(m_replies)) {
        if (r && r->isRunning()) {
            allFinished = false;
            break;
        }
    }
    
    if (allFinished) {
        m_status = Completed;
        m_endTime = QDateTime::currentDateTime();
        m_speedTimer->stop();
        m_retryCount = 0; // 下载成功，重置重试次数
        emit statusChanged(m_status);
        emit downloadFinished();
    }
    
    reply->deleteLater();
    m_replies[segmentIndex] = nullptr;
}

void DownloadItem::onSegmentError(QNetworkReply::NetworkError error)
{
    Q_UNUSED(error);
    
    QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
    if (!reply) return;
    
    m_speedTimer->stop();
    m_status = Error;
    emit statusChanged(m_status);
    emit downloadError(reply->errorString());
    
    // 停止所有其他段的下载
    stopMultiThreadDownload();
    
    // 安排重试
    scheduleRetry();
}

void DownloadItem::onSegmentProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    Q_UNUSED(bytesReceived);
    Q_UNUSED(bytesTotal);
    
    // 更新总下载大小
    qint64 totalDownloaded = 0;
    for (qint64 size : qAsConst(m_segmentDownloaded)) {
        totalDownloaded += size;
    }
    m_downloadedSize = totalDownloaded;
    
    if (m_fileSize > 0) {
        m_progress = static_cast<int>((m_downloadedSize * 100) / m_fileSize);
        emit progressChanged(m_progress);
    }
}

void DownloadItem::onRetryTimeout()
{
    // 重试定时器超时，重新开始下载
    if (m_retryCount < m_maxRetries) {
        m_retryCount++;
        qDebug() << "Retrying download (" << m_retryCount << "/" << m_maxRetries << ")";
        start(); // 重新开始下载
    } else {
        // 达到最大重试次数，报告错误
        qDebug() << "Maximum retries reached, download failed";
        m_status = Error;
        emit statusChanged(m_status);
        emit downloadError("达到最大重试次数，下载失败");
    }
}

void DownloadItem::updateFileName()
{
    QUrl url(m_url);
    QString fileName = QFileInfo(url.path()).fileName();
    
    if (fileName.isEmpty()) {
        fileName = "download_" + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    }
    
    m_fileName = fileName;
}

void DownloadItem::startMultiThreadDownload()
{
    // 先获取文件大小
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest headRequest;
    headRequest.setUrl(QUrl(m_url));
    
    QNetworkReply *headReply = manager->head(headRequest);
    
    // 等待HEAD请求完成以获取文件信息
    QEventLoop loop;
    connect(headReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    
    if (headReply->error() != QNetworkReply::NoError) {
        // 如果HEAD请求失败，回退到单线程下载
        QString errorString = headReply->errorString();
        headReply->deleteLater();
        manager->deleteLater();
        m_maxConnections = 1;
        
        // 发送错误信息
        emit downloadError(QString("无法获取文件信息: %1").arg(errorString));
        m_status = Error;
        emit statusChanged(m_status);
        
        // 安排重试
        scheduleRetry();
        return;
    }
    
    // 获取文件大小
    QVariant contentLength = headReply->header(QNetworkRequest::ContentLengthHeader);
    if (!contentLength.isValid()) {
        // 如果无法获取文件大小，回退到单线程下载
        headReply->deleteLater();
        manager->deleteLater();
        m_maxConnections = 1;
        
        // 发送错误信息
        emit downloadError("无法获取文件大小，将使用单线程下载");
        start();
        return;
    }
    
    m_fileSize = contentLength.toLongLong();
    headReply->deleteLater();
    manager->deleteLater();
    
    if (m_fileSize <= 0) {
        m_maxConnections = 1;
        
        // 发送错误信息
        emit downloadError("文件大小无效，将使用单线程下载");
        start();
        return;
    }
    
    // 初始化段信息
    m_replies.resize(m_maxConnections);
    m_segmentSizes.resize(m_maxConnections);
    m_segmentDownloaded.resize(m_maxConnections);
    
    for (int i = 0; i < m_maxConnections; ++i) {
        m_segmentDownloaded[i] = 0;
    }
    
    // 计算每段大小
    qint64 segmentSize = m_fileSize / m_maxConnections;
    for (int i = 0; i < m_maxConnections; ++i) {
        m_segmentSizes[i] = (i == m_maxConnections - 1) ? 
                            (m_fileSize - i * segmentSize) : segmentSize;
    }
    
    // 创建并启动每个段的下载
    for (int i = 0; i < m_maxConnections; ++i) {
        QNetworkAccessManager *segmentManager = new QNetworkAccessManager(this);
        QNetworkRequest request;
        request.setUrl(QUrl(m_url));
        
        // 设置Range头以下载文件的特定部分
        qint64 startByte = i * segmentSize;
        qint64 endByte = startByte + m_segmentSizes[i] - 1;
        QString range = QString("bytes=%1-%2").arg(startByte).arg(endByte);
        request.setRawHeader("Range", range.toLatin1());
        
        QNetworkReply *reply = segmentManager->get(request);
        m_replies[i] = reply;
        
        connect(reply, &QNetworkReply::readyRead, this, &DownloadItem::onSegmentReadyRead);
        connect(reply, &QNetworkReply::finished, this, &DownloadItem::onSegmentFinished);
        connect(reply, &QNetworkReply::errorOccurred, this, &DownloadItem::onSegmentError);
        connect(reply, &QNetworkReply::downloadProgress,
                this, &DownloadItem::onSegmentProgress);
    }
}

void DownloadItem::stopMultiThreadDownload()
{
    m_speedTimer->stop();
    
    for (QNetworkReply *reply : qAsConst(m_replies)) {
        if (reply) {
            reply->abort();
            reply->deleteLater();
        }
    }
    m_replies.clear();
    m_segmentSizes.clear();
    m_segmentDownloaded.clear();
}

void DownloadItem::scheduleRetry()
{
    if (m_retryCount < m_maxRetries) {
        // 设置重试间隔（指数退避策略）
        int retryDelay = 1000 * (1 << m_retryCount); // 1秒, 2秒, 4秒...
        if (retryDelay > 30000) retryDelay = 30000; // 最大30秒
        
        qDebug() << "Scheduling retry in" << retryDelay << "ms";
        m_retryTimer->start(retryDelay);
    } else {
        // 达到最大重试次数，报告错误
        qDebug() << "Maximum retries reached, download failed";
        m_status = Error;
        emit statusChanged(m_status);
        emit downloadError("达到最大重试次数，下载失败");
    }
}